#! /usr/bin/env bash

set -o errexit
set -o nounset
set -o pipefail

umask 0022
unset IFS
unset OFS
unset LD_PRELOAD
unset LD_LIBRARY_PATH

export PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'

SENTRY_VERSION=$(cat res/config.yaml | grep "name: sentry" -A 4 | grep version |awk '{print $2}' | sed 's/ //g')
BASE_OPERATOR_TAG=$(cat res/config.yaml | grep "name: base-operator$" -A 4 | grep version |awk '{print $2}' | sed 's/ //g')
BASE_OPERATOR_VERSION=${BASE_OPERATOR_TAG%-manifest*}
KIND_NODE_VERSION=$(cat res/config.yaml | grep "name: kind-node" -A 4 | grep version |awk '{print $2}' | sed 's/ //g')
KUBE_NODE_VERSION=$(cat res/config.yaml | grep "name: kube-node" -A 4 | grep version |awk '{print $2}' | sed 's/ //g')
MINIALAUDA_VERSION=$(cat res/config.yaml | grep "name: minialauda" -A 4 | grep version |awk '{print $2}' | sed 's/ //g')

REGISTRY_VERSION=$(cat res/config.yaml | grep "name: registry$" -A 4 | grep version |awk '{print $2}' | sed 's/ //g')
PACKAGE_TYPE=$(cat res/config.yaml | grep packageType | awk '{print $2}')
PACKAGE_EDITION=$(cat res/config.yaml | grep packageEdition | awk '{print $2}')
CPASS_DIR=/cpaas
REGISTRY_IMAGE="ait/registry:$REGISTRY_VERSION"
INSTALLER_PORT=8080
ENABLE_CUSTOMER_DEFINED_PORTS=false
ARCH="x86"
REGISTRY="172.17.0.1:11443"
USERNAME=${USERNAME:-""}
PASSWORD=${PASSWORD:-""}
HOST_API_SERVER_PORT=16443
HOST_CONSOLE_HTTP_PORT=12080
HOST_CONSOLE_HTTPS_PORT=12443
NETWORK_MODE=ovn
if [ $PACKAGE_EDITION == 'Runtime' ]; then
NETWORK_MODE=calico
fi
# 命令行示例
# base setup.sh --network-mode calico --enabled-customer-defined-ports
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
    --enabled-customer-defined-ports)   # 启用自定义端口开关
    ENABLE_CUSTOMER_DEFINED_PORTS=true
    shift # remove --enabled-customer-defined-ports
    ;;
    --registry)   # registry url
    REGISTRY="$2"
    shift 2
    ;;
    --username)   # registry username
    USERNAME="$2"
    shift 2
    ;;
    --password)   # registry password
    PASSWORD="$2"
    shift 2
    ;;
    -n|--network-mode)  # 支持ovn、calico、flannel
    NETWORK_MODE="$2"
    shift # past argument
    shift # past value
    ;;
    *)
    echo unknown key $key
    exit 1
    ;;
esac
done

CUSTOM_DIRS=($CPASS_DIR $CPASS_DIR/data $CPASS_DIR/conf $CPASS_DIR/hooks $CPASS_DIR/registry $CPASS_DIR/res)
for dir in ${CUSTOM_DIRS[@]}
do
  test -d $dir || mkdir $dir
done

REGISTRY_OPTIONS="-d --restart=always -u root --privileged=true --name pkg-registry
-p 11443:5000
-v $(pwd)/registry:/var/lib/registry
"

function get_arch() {
  os_arch=$(uname -m)
  if [[ "$os_arch" =~ "x86" ]]
  then
    ARCH="x86"
  elif [[ "$os_arch" =~ "aarch" ]]
  then
    ARCH="arm64"
  fi
}

function prefight() {
  echo "Step.1 prefight"

  check_root
  check_selinux

  cp res/hooks/* /cpaas/hooks/
  chmod +x /cpaas/hooks/*

  chmod +x res/acp-post-install
  cp res/acp-post-install /cpaas/res/
  get_arch
}

function command_exists() {
    command -v "$@" > /dev/null 2>&1
}

function check_selinux() {
  if command_exists getenforce
  then
    if ! getenforce | grep -q Disabled
    then
      echo "selinux not disabled"
      exit 1
    fi
    echo "selinux is disabled"
  fi
}

function check_root() {
  if [ "root" != "$(whoami)" ]; then
    echo "only root can execute this script"
    exit 1
  fi
  echo "root: yes"
}

function check_disk() {
  local -r path=$1
  local -r size=$2

  disk_avail=$(df -BG "$path" | tail -1 | awk '{print $4}' | grep -oP '\d+')
  if ((disk_avail < size)); then
    echo "available disk space for $path needs be greater than $size GiB"
    exit 1
  fi

  echo "available disk space($path):  $disk_avail GiB"
}

function ensure_docker() {
  echo "Step.2 ensure docker is ok"

  if ! [ -x "$(command -v docker)" ]; then
    echo "command docker not find"
    install_docker
  fi
  if ! systemctl is-active --quiet docker; then
    echo "docker status is not running"
    install_docker
  fi
  if [ "$USERNAME" != "" ] && [ "$PASSWORD" != "" ]; then
    docker login $REGISTRY -u $USERNAME -p $PASSWORD > /dev/null 2>&1
  fi
}

function install_docker() {
  echo "install docker [doing]"

  cat <<EOF > $CPASS_DIR/data/daemon.json
{
  "debug": false,
  "insecure-registries": [
    "0.0.0.0/0"
  ],
  "ip-forward": true,
  "ipv6": false,
  "live-restore": true,
  "log-driver": "json-file",
  "log-level": "warn",
  "log-opts": {
    "max-size": "100m",
    "max-file": "2"
  },
  "selinux-enabled": false,
  "experimental" : true,
  "storage-driver": "overlay2"
}
EOF

  tar xvaf "res/${ARCH}/docker.tgz" -C /usr/bin --strip-components=1
  cp -v res/docker.service /etc/systemd/system
  test -d /etc/docker || mkdir -p /etc/docker
  cp -v $CPASS_DIR/data/daemon.json /etc/docker/

  systemctl daemon-reload
  systemctl enable docker

  # because first start docker may be restart some times
  systemctl restart docker || :
  maxSecond=60
  for i in $(seq 1 $maxSecond); do
    if systemctl is-active --quiet docker; then
      break
    fi
    sleep 1
  done
  if ((i == maxSecond)); then
    echo "start docker failed, please check docker service."
    exit 1
  fi
  echo "install docker [ok]"
}

function load_image() {
  if [ "$PACKAGE_TYPE" == "FULL" ]; then
    echo "Step.3 load images [doing]"
    docker load -i res/${ARCH}/registry.tar
    echo "Step.3 load images [ok]"
  else
    echo "Step.3 skip load images"
  fi
}

function install_registry() {
  if [ "$PACKAGE_TYPE" == "FULL" ]; then
    echo "Step.4 install registry [doing]"
    if docker ps | grep -q pkg-registry
    then
      docker restart pkg-registry
    else
      docker run $REGISTRY_OPTIONS ${REGISTRY_IMAGE}
    fi
    echo  "Setp.4 install registry [ok]"
  else
    echo  "Setp.4 skip install registry"
  fi
}

function start_minialauda() {
  echo "Step.5 start start_minialauda [doing]"

  docker rm -f minialauda-control-plane >/dev/null 2>&1 || :
  docker volume prune -f >/dev/null 2>&1 || :

  docker run --name minialauda -v /tmp:/tmp --rm $REGISTRY/ait/minialauda:$MINIALAUDA_VERSION cp /opt/output/minialauda /tmp/
  mv /tmp/minialauda /usr/bin/minialauda

  ip addr | grep -w inet | awk '{print $2}' > $CPASS_DIR/data/local-ips
  ips=$(ip addr | awk '/^[0-9]+: / {}; /inet.*global/' | awk '{print $2}' | awk -F / '{print $1}')
  echo $NETWORK_MODE > $CPASS_DIR/data/network-mode
  echo $(pwd) > $CPASS_DIR/data/installer-path

  cat <<EOF > $CPASS_DIR/data/minialauda.cfg
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraMounts:
  - hostPath: /etc/resolv.conf
    containerPath: /etc/resolv.conf
  - hostPath: $CPASS_DIR
    containerPath: /cpaas
  - hostPath: $(pwd)/res
    containerPath: /cpaas/res
  extraPortMappings:
  - containerPort: 8080
    hostPort: 8080
    protocol: TCP
  - containerPort: 80
    hostPort: $HOST_CONSOLE_HTTP_PORT
    protocol: TCP
  - containerPort: 443
    hostPort: $HOST_CONSOLE_HTTPS_PORT
    protocol: TCP
defaultPortsConfigured: true
networking:
  apiServerPort: $HOST_API_SERVER_PORT
EOF

  minialauda create cluster --retain --sentry-version=$SENTRY_VERSION --base-operator-version=$BASE_OPERATOR_VERSION --image=$REGISTRY/ait/kind-node:$KIND_NODE_VERSION --registry=$REGISTRY --registry-username=$USERNAME --registry-password=$PASSWORD --acp-mode=mini --config=$CPASS_DIR/data/minialauda.cfg 2>&1
  minialauda export kubeconfig && mv /root/.kube/config $CPASS_DIR/data/alauda.kubeconfig && rm -rf /root/.kube
  mkdir -p /tmp/tmp
  docker run --rm -v /tmp/tmp:/data/usr_bin $REGISTRY/ait/kube-node:$KUBE_NODE_VERSION 2>/dev/null || true
  cp /tmp/tmp/kubectl $CPASS_DIR/data/kubectl
  rm -rf /tmp/tmp

  echo "Step.5 start start_minialauda [ok]"

  echo "Please use your browser which can connect this machine to open http://127.0.0.1:$INSTALLER_PORT for installing global!"

  if [ -n "$ips" ]
  then
    echo "You can also visit the following address:"
    for ip in ${ips[@]}
    do
      echo "http://$ip:$INSTALLER_PORT"
    done
  fi
}

function install_captain() {
  if [ "$PACKAGE_TYPE" == "FULL" ]; then
    chmod 555 $(pwd)/res/${ARCH}/helm3
    chmod 555 $(pwd)/res/${ARCH}/kubectl-captain
    /bin/cp $(pwd)/res/${ARCH}/kubectl-captain /usr/local/bin/
  fi
}

prefight
ensure_docker
install_captain
load_image
install_registry
start_minialauda
